#ifndef BLEEDTHROUGHEVALUATION_HPP
#define BLEEDTHROUGHEVALUATION_HPP


#include <math.h>
#include <iostream>
#include <map>


#include "BleedThroughTrinarisation.hpp"


/*!
  * \brief Hides the use of void *
  * \see MeasureParameters
  */

struct ParameterConst
{
    ParameterConst()
        : _param(NULL){}

    template <class T>
    void setParam(const T * param)
    {_param = param;}

    template <class T>
    const T * getParam()
    {return (T * )_param;}

    const void *_param;
};

/*!
  *
  * \brief Abstract class in which measure needed parameters (images or thresholds) are stored in a map
  * \see std::map
  * \see ParameterConst
  *
  * Each parameter as a key (std::string) and a value of type ParameterConst (\see ParameterConst).
  * \code
  *
  * MesureTemplateMethod * method = facade.selectMeasure(chosenMeasures.at(i));
  * MeasureParameters *params = method->creatParameters();
  * if(params->contains("verso")){
  *         params->setParamByName("verso",&verso);
  * }
  * method->initWithParameters(params);
  * cout << "RESULT : " << method->evaluate(recto) << std::endl;
  * \endcode
  */
class MeasureParameters
{
public :
    virtual bool isValid() = 0;

    std::map<std::string, ParameterConst *> params;

    template <class T>
    const T * getParamByName(std::string name)
    {return params[name]->getParam<T>();}

    template <class T>
    void addNewParamByName(std::string name)
    {params[name] = new ParameterConst;}

    template <class T>
    void setParamByName(std::string name,const T* param)
    {return params[name]->setParam(param);}

    bool contains(std::string name)
    {return params.find(name)!=params.end();}

    MeasureParameters ()
    {}

};


/**
  * @todo rename file ET doxydoc
  */
class MesureTemplateMethod
{
public:
    MesureTemplateMethod()
        : _params(NULL), ready(false)
    {}

    /**
      * Runs the Method
      */
    virtual float evaluate(const girl::tools::Image &image) =0;


    virtual bool parametersOk()
    {return ready;}


    virtual MeasureParameters *  creatParameters() = 0;

    /**
      * \throws Exceptions::MessageException if pParams is not valid
      * \see MeasureParameters::isValid()
      */
    virtual void initWithParameters(MeasureParameters *pParams)
    {
        if(pParams->isValid()){
            setParameters(pParams);
            init();
            setReady();
        }
        else throw Exceptions::MessageException("Parameters are not valid (image may be null)");
    }
    virtual void init(){}

    virtual std::string getName() = 0;

protected :
    virtual void clamp(int  &x,int &y, const girl::tools::Image &image) const;
    virtual void setReady()
    {ready = true;}
    virtual bool setParameters(MeasureParameters *pParams)
    {_params = pParams;}


protected :
    MeasureParameters *_params;
    bool ready;
};



#endif // BLEEDTHROUGHEVALUATION_HPP
